import {
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { verify } from 'jsonwebtoken';
import { CacheService } from '../cache/cache.service';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  constructor(
    private reflector: Reflector,
    private readonly configService: ConfigService,
    private readonly cacheService: CacheService,
  ) {
    super();
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const isPublic = this.reflector.getAllAndOverride('isPublic', [
      context.getHandler(),
      context.getClass(),
    ]);

    if (isPublic) return true;

    const request = context.switchToHttp().getRequest();
    const accessToken = request.headers['authorization'];
    const jwt = this.configService.get('jwt');
    if (accessToken) {
      let userInfo, access_token;
      try {
        userInfo = verify(accessToken.slice(7), jwt.secret);
        access_token = accessToken.slice(7);
      } catch (err) {
        throw new UnauthorizedException('token失效');
      }
      const redis_token = await this.cacheService.get(
        `access_token_${userInfo.id}`,
      );
      if (redis_token !== access_token) {
        throw new UnauthorizedException('token失效');
      }
      try {
        const decodeAccessToken: any = verify(accessToken.slice(7), jwt.secret);
        // 解析access_token信息并存放到request.headers中
        request.headers.user = decodeAccessToken;
      } catch (err) {
        const { exp } = err;
        throw new UnauthorizedException(
          exp ? `token已于${new Date(+exp).toLocaleString()}失效` : 'token失效',
        );
      }
    } else {
      throw new UnauthorizedException('token失效');
    }

    return true;
  }
}
